package com.lagou.java;

import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Gobang {

    private char[][] chessboard;  //棋盘
    private boolean black; //是否黑子下棋
    private boolean win;

    /*
     * 实例化时，赋值给棋盘
     * */
    public Gobang() {
        this.chessboard = new char[17][17];
        this.black = true;
        this.win = false;
        //遍历数组赋值
        for(int i = 0; i < 17; i++){
            for(int j = 0; j < 17; j++){
                //ASCII码 0~9 为48~57 a~f 为97~102 空白符为32 +为43 \u25cb ○ 黑子 \u25cf ● 白子
                if(0 == i && 0 == j){
                    this.chessboard[i][j] = (char)32;
                }else if ((0 == i && j < 11)){
                    this.chessboard[i][j] = (char)(j + 47);
                }else if (0 == i){
                    this.chessboard[i][j] = (char)(j + 86);
                }else if ((0 == j && i < 11)){
                    this.chessboard[i][j] = (char)(i + 47);
                }else if (0 == j){
                    this.chessboard[i][j] = (char)(i + 86);
                }else {
                    this.chessboard[i][j] = (char)43;
                }
            }
        }
    }

    public boolean isWin() {
        return win;
    }

    /*
    *   绘制棋盘的方法
    * */
    private void printChessBoard(char[][] chessboard){
        for(int i = 0; i < 17; i++){
            for(int j = 0; j < 17; j++){
                System.out.print(chessboard[i][j] + " ");
            }
            System.out.println();
        }
    }

    /*
    *   提示黑方和白方分别下棋并重新绘制棋盘
    * */
    public void playChess(){
        boolean pointIsLegal = true;

        System.out.println("请" + (black ? "黑方":"白方") + "下棋，请输入棋子坐标值x，值为[0 , f]");
        Scanner sc = new Scanner(System.in);
        String xPointStr = sc.next();
        System.out.println("请输入棋子坐标值y，值为[0 , f]");
        String yPointStr = sc.next();

        //正则表达式匹配0-9 a-f
        String pattern = "[0-9a-f]";
        if (this.pointIsLegal(xPointStr, pattern) && this.pointIsLegal(yPointStr, pattern)) {
            //需要判断此坐标点是不是已经下了黑棋或者白棋
            if ('+' != this.chessboard[strToInt(yPointStr)][strToInt(xPointStr)]) {
                System.out.println((black ? "黑方":"白方") + "输入棋子坐标值不合法!该坐标已有棋子!");
            } else {
                this.chessboard[strToInt(yPointStr)][strToInt(xPointStr)]= (black ? '\u25cb':'\u25cf');
                printChessBoard(this.chessboard);
                Win(strToInt(xPointStr), strToInt(yPointStr), this.chessboard[strToInt(yPointStr)][strToInt(xPointStr)], black);
                black = !black;
            }
        } else {
            System.out.println((black ? "黑方":"白方") + "输入棋子坐标值不合法!");
        }
    }

    /*
     *   每当一方下棋后判断是否获胜 任意方向满五个即可胜利
     * */
    private void Win(int x,int y, char c,boolean black){
        if (vertical(x, y, c)||horizontal(x, y, c)||topLeftToBottomRight(x, y, c)||topRightToBottomLeft(x, y, c)) {
            System.out.println((black ? "黑方":"白方") + "获胜!");
            this.win = true;
        }
    }
    /*
    *   竖直方向判断
    * */
    private boolean vertical(int x,int y, char c) {
        int count = 1;
        // 从(x, y)坐标点往上探索，元素值一样的就计数+1，不一样就不在探索
        for (int i =y - 1; i > 0; i--) {
            if (c == this.chessboard[i][x]) {
                count++;
            } else {
                break;
            }
        }
        // 从(x, y)坐标点往下探索，元素值一样的就计数+1，不一样就不在探索
        for (int i = y + 1; i < this.chessboard.length; i++) {
            if (c == this.chessboard[i][x]) {
                count++;
            } else {
                break;
            }
        }
        return count >= 5;
    }

    /*
    *   水平方向判断
    * */
    private boolean horizontal(int x,int y, char c){
        int count = 1;
        // 从(x, y)坐标点往左探索，元素值一样的就计数+1，不一样就不在探索
        for (int i =x - 1; i > 0; i--) {
            if (c == this.chessboard[y][i]) {
                count++;
            } else {
                break;
            }
        }
        // 从(x, y)坐标点往下探索，元素值一样的就计数+1，不一样就不在探索
        for (int i = x + 1; i < this.chessboard.length; i++) {
            if (c == this.chessboard[y][i]) {
                count++;
            } else {
                break;
            }
        }
        return count >= 5;
    }

    /*
    *   左上到右下方向判断
    * */
    private boolean topLeftToBottomRight(int x,int y, char c){
        int count = 1;
        // 从(x, y)坐标点往左上探索，元素值一样的就计数+1，不一样就不在探索
        for (int i = x-1,j = y-1; i > 0 && j > 0 ; i--,j--) {
            if (c == this.chessboard[j][i]){
                count++;
            } else {
                break;
            }
        }
        // 从(x, y)坐标点往右下探索，元素值一样的就计数+1，不一样就不在探索
        for (int i = x+1,j = y+1; i < this.chessboard.length && j < this.chessboard.length ; i++,j++) {
            if (c == this.chessboard[j][i]){
                count++;
            } else {
                break;
            }
        }
        return count >= 5;
    }

    /*
     *   右上到左下方向判断
     * */
    private boolean topRightToBottomLeft(int x,int y, char c){
        int count = 1;
        // 从(x, y)坐标点往右上探索，元素值一样的就计数+1，不一样就不在探索
        for (int i = x+1,j = y-1; i < this.chessboard.length && j > 0 ; i++,j--) {
            if (c == this.chessboard[j][i]){
                count++;
            } else {
                break;
            }
        }
        // 从(x, y)坐标点往左下探索，元素值一样的就计数+1，不一样就不在探索
        for (int i = x-1,j = y+1; i > 0 && j < this.chessboard.length ; i--,j++) {
            if (c == this.chessboard[j][i]){
                count++;
            } else {
                break;
            }
        }
        return count >= 5;
    }

    /*
    *   判断坐标值是否合法[0 , f]
    * */
    private boolean pointIsLegal(String str, String pattern){
        Pattern r = Pattern.compile(pattern);
        Matcher m = r.matcher(str);
        return m.matches();
    }

    /*
    *   把坐标值转换成数字
    * */
    private int strToInt(String str) {
        if (pointIsLegal(str, "[0-9]")) {
            return Integer.parseInt(str) + 1;
        }
        // a~f 转换为数字 a~f 为97~102
        return (str.charAt(0) - 86);
    }
}
